#include "Desires.h"
#include "World.h"

Desires::Desires(const std::string& behaviour)
{
	behaviour__ = behaviour ;
	std::string real_path = "./baseq3/behaviours/" + behaviour;
	std::ifstream is(real_path.c_str(), std::ios_base::in);
	if (!is.is_open())
		throw Exception("Could not open file: " + real_path, __FILE__, __LINE__);

	while (!is.eof())
	{
		std::pair<std::string, float> p;

		is >> p.first;
		is >> p.second;

		if (p.first != "")
			desires__.insert(p);
	}

	is.close();
} 


// return the name of the behaviour template
std::string Desires::getBehaviourName()
{
       return behaviour__;
}


std::map<std::string,float>& Desires::getList()
{
	return desires__ ;
}


// get a desire's value using the name
float Desires::getDesireValue(std::string desire)
{
       if(desires__.find(desire) == desires__.end())
		{
			return -1 ;
		}
		else
		{
			return desires__[desire];
		}
}


// returns current highest desire
std::pair<std::string,float> Desires::getHighestValue()
{
       std::map<std::string,float>::iterator it = desires__.begin();
       std::pair<std::string,float> highest = *it;
       while(it != desires__.end())
       {
                if((*it).second >= highest.second)
                {
                              highest = (*it) ;
                }
            it++;    
       }
   return highest ;    
}

// set a desire's value using a modifier
bool Desires::applyModifier(std::pair<std::string,float> modifier)
{
	// if the desire is enabled in the current behaviour
       if(desires__.find(modifier.first) != desires__.end())
	{
		// the desire's value cannot exceed the max 
		float newValue = getDesireValue(modifier.first) + modifier.second ;
		if(newValue > 1)
		{
			newValue = 1 ;
		}
		// and cannot be less than 0 
		if(newValue <= 0)
		{
			newValue = 0 ;
		}

		// apply the modifier
		desires__[modifier.first] = newValue ;

		return true ;
	}
	else
	{
		// else ignore it and return false
		return false ;
	}

	return false ;
}

// increase all desires naturally
void Desires::naturalGrowth()
{
	float timeSinceLastFrame = World::getWorld()->elapsedTime() ;

	std::map<std::string,float>::iterator it = desires__.begin();

	// for each desire in the list
       	while(it != desires__.end())
	{
		std::pair<std::string,float> current = *it;
		
		World * w = World::getWorld();
		
		// we get a random number between 1/80 and -1/80  
		float minusFactor = w->randf() ;
		float rand ;
		// the desire has 0.8 out of 1 chance to be increased and 0.2 to be decreased
		if(minusFactor <= 0.8)
		{
			rand = (w->randf())*timeSinceLastFrame ;
		}
		else
		{
			rand = -(w->randf())*timeSinceLastFrame/4 ;
		}

		// and apply it to the desire
		// the desire's value cannot exceed the max 
		float newValue = getDesireValue(current.first) + rand ;
		if(newValue >= 0.21f)
		{
			newValue = getDesireValue(current.first) ;
		}
		// and cannot be less than 0 
		if(newValue <= 0)
		{
			newValue = 0 ;
		}

		// apply the modifier
		desires__[current.first] = newValue ;

		it++ ;
		
	}
}

// apply a reward to all desires concerned
void Desires::applyReward(std::list<std::pair<std::string,float> > reward)
{
	while(reward.size() != 0)
	{
		applyModifier(reward.front());
		reward.pop_front();
	}
}

std::ostream& operator<< (std::ostream& os, const Desires& d)
{
	std::map<std::string,float>::const_iterator it = d.desires__.begin();

       	while(it != d.desires__.end())
	{
		std::pair<std::string,float> current = *it;
		os << current.first << " : " << current.second << std::endl ;
		it++ ;
	}

	return os;
}

